package org.xx.armory.rpc.decorators;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xx.armory.db.DataSourceStorage;
import org.xx.armory.db.TransactionManager;
import org.xx.armory.db.impl.ThreadContextTransactionManager;
import org.xx.armory.rpc.Decorator;
import org.xx.armory.security.AuthenticationToken;

import javax.sql.DataSource;

import static org.xx.armory.commons.Validators.notBlank;
import static org.xx.armory.commons.Validators.notEmpty;
import static org.xx.armory.commons.Validators.notNull;

/**
 * 使用数据库验证授权的修饰器。
 */
public abstract class AbstractDbContextAuthorizationDecorator
        extends AbstractAuthorizationDecorator
        implements Decorator {
    private final Logger logger = LoggerFactory.getLogger(AbstractDbContextAuthorizationDecorator.class);

    private DataSource dataSource;
    private TransactionManager transactionManager;
    private String dataSourceName;

    /**
     * 获取数据源的名字。
     *
     * @return 数据源的名字。
     */
    public final String getDataSourceName() {
        return dataSourceName;
    }

    /**
     * 设置数据源的名字。
     *
     * @param dataSourceName
     *         数据源的名字。
     * @throws IllegalArgumentException
     *         如果参数{@code dataSourceName}是{@code null}或者只包含空白字符。
     */
    public final void setDataSourceName(
            String dataSourceName
    ) {
        this.dataSourceName = notBlank(dataSourceName, "dataSourceName").trim();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void initialize()
            throws Exception {
        super.initialize();

        // 加载数据源。
        this.dataSource = DataSourceStorage.getDataSource(this.dataSourceName);

        // 创建事务管理器。
        this.transactionManager = new ThreadContextTransactionManager();
        this.transactionManager.setDataSource(this.dataSource);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void dispose()
            throws Exception {
        // 关闭事务管理器。
        if (this.transactionManager instanceof AutoCloseable) {
            try {
                ((AutoCloseable) this.transactionManager).close();
            } catch (Exception ex) {
                logger.warn("cannot close transaction manager", ex);
            }
        }

        // 关闭数据源。
        if (this.dataSource instanceof AutoCloseable) {
            try {
                ((AutoCloseable) this.dataSource).close();
            } catch (Exception ex) {
                logger.warn("cannot close data source", ex);
            }
        }

        super.dispose();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected final boolean isPermitted(
            AuthenticationToken token,
            int[] permissions
    )
            throws Exception {
        notNull(token, "token");
        notEmpty(permissions, "permissions");

        try {
            return isPermitted(token, permissions, this.transactionManager);
        } finally {
            this.transactionManager.current().close();
        }
    }

    /**
     * 判断指定的令牌是否具有指定的权限。
     *
     * @param token
     *         令牌
     * @param permissions
     *         指定的权限。
     * @param transactionManager
     *         用于访问数据库的事务管理器。
     * @return 如果具有指定的权限则返回{@code true}，否则返回{@code false}。
     * @throws IllegalArgumentException
     *         如果参数{@code token}是{@code null}或者参数{@code permissions}是{@code null}或者长度为0。
     */
    protected abstract boolean isPermitted(
            AuthenticationToken token,
            int[] permissions,
            TransactionManager transactionManager
    )
            throws Exception;
}
